// -*- c++ -*-
#ifndef __CVECTOR2DFIXED16_H__
#define __CVECTOR2DFIXED16_H__

#include "StdDefs.h"
#include "CMathFixed16.h"
 


// CVector2dCVector2dFixed16* must maintain casting ability with (fixed16*).
// CVector2dCVector2dFixed16 may not have virtuals, inherited, or instantiated data.


class CVector2dFixed16
{
public:
	inline explicit CVector2dFixed16( no_ctor_modify n ) { }
	CVector2dFixed16(){}
	CVector2dFixed16( fixed16 degrees );
	CVector2dFixed16( const fixed16* ij );
	CVector2dFixed16( fixed16 i, fixed16 j ); 
	CVector2dFixed16( const CVector2dFixed16& v ); 
	~CVector2dFixed16(){}

	fixed16				Length() const;

	CVector2dFixed16&	Clear();
	CVector2dFixed16&	Set( fixed16 i, fixed16 j );
	CVector2dFixed16&	Set( const CVector2dFixed16& v );
	CVector2dFixed16&	Normalize();
	CVector2dFixed16&	LerpTo( const CVector2dFixed16& v, fixed16 u ); 
	CVector2dFixed16&	Rotate( fixed16 degrees );

	fixed16				Angle() const;
	fixed16				Angle( CVector2dFixed16& v ) const;
	fixed16				AngleTo( CVector2dFixed16& v ) const;

	fixed16				ShortestDistanceToLineSegment( const CVector2dFixed16& segV0, const CVector2dFixed16& segV1,
													   CVector2dFixed16& pntOfIntersection ) const;

	fixed16				IsOnLineSegment( const CVector2dFixed16& segV0, const CVector2dFixed16& segV1 ) const;

	fixed16				IsInPoly( const CVector2dFixed16* vertex, int vertexCount ) const;

	CVector2dFixed16&			operator=( fixed16 degrees );
	CVector2dFixed16&			operator=( const fixed16* ij );

	CVector2dFixed16&			operator+=( const CVector2dFixed16& v );
	CVector2dFixed16&			operator+=( fixed16 val );
	CVector2dFixed16&			operator-=( const CVector2dFixed16& v );
	CVector2dFixed16&			operator-=( fixed16 val );
	CVector2dFixed16&			operator*=( fixed16 val );
	CVector2dFixed16&			operator/=( fixed16 val );

	fixed16&				operator[]( uint32 idx );
	fixed16				operator[]( uint32 idx ) const;

	friend CVector2dFixed16	operator+( const CVector2dFixed16& v1, const CVector2dFixed16& v2 );
	friend CVector2dFixed16	operator+( const CVector2dFixed16& v, fixed16 val );
	friend CVector2dFixed16	operator+( fixed16 val, const CVector2dFixed16& v );
	friend CVector2dFixed16	operator-( const CVector2dFixed16& v1, const CVector2dFixed16& v2 );
	friend CVector2dFixed16	operator-( const CVector2dFixed16& v, fixed16 val );
	friend CVector2dFixed16	operator-( fixed16 val, const CVector2dFixed16& v );
	friend fixed16		operator*( const CVector2dFixed16& v1, const CVector2dFixed16& v2 );
	friend CVector2dFixed16	operator*( const CVector2dFixed16& v, fixed16 val );
	friend CVector2dFixed16	operator*( fixed16 val, const CVector2dFixed16& v );
	friend CVector2dFixed16	operator/( const CVector2dFixed16& v, fixed16 val );
	friend CVector2dFixed16	operator/( fixed16 val, const CVector2dFixed16& v );
	
	fixed16				m_i; 
	fixed16				m_j;
};


 

inline 
CVector2dFixed16::CVector2dFixed16( fixed16 degrees )
{ 
	m_i = CMathFixed16::Cos( degrees );
	m_j = CMathFixed16::Sin( degrees );
}


inline 
CVector2dFixed16::CVector2dFixed16( const fixed16* ij )
{ 
	ASSERT( ij );

	m_i = *ij;
	m_j = *( ij + 1 );
}


inline 
CVector2dFixed16::CVector2dFixed16( fixed16 i, fixed16 j )
{ 
	m_i = i; 
	m_j = j; 
}


inline 
CVector2dFixed16::CVector2dFixed16( const CVector2dFixed16& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 
}


inline
fixed16 CVector2dFixed16::Length() const
{
	return CMathFixed16::Sqrt( ( *this * *this ) );
}


inline
CVector2dFixed16& CVector2dFixed16::Clear()
{
	m_i = 0; 
	m_j = 0;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::Set( fixed16 i, fixed16 j )
{
	m_i = i; 
	m_j = j;

	return *this;
}


inline 
CVector2dFixed16& CVector2dFixed16::Set( const CVector2dFixed16& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 

	return *this;
}



inline
CVector2dFixed16& CVector2dFixed16::Normalize()
{
	fixed16 len = Length();

	if( len )
		*this /= len;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator=( fixed16 degrees )
{
	m_i = CMathFixed16::Cos( degrees );
	m_j = CMathFixed16::Sin( degrees );

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator=( const fixed16* ij )
{
	ASSERT( ij );

	m_i = *ij;
	m_j = *( ij + 1 );

	return *this;
}
	

inline
CVector2dFixed16& CVector2dFixed16::operator+=( const CVector2dFixed16& v )
{
	m_i += v.m_i;
	m_j += v.m_j;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator+=( fixed16 val )
{
	m_i += val;
	m_j += val;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator-=( const CVector2dFixed16& v )
{
	m_i -= v.m_i;
	m_j -= v.m_j;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator-=( fixed16 val )
{
	m_i -= val;
	m_j -= val;

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator*=( fixed16 val )
{
	m_i = CMathFixed16::Mul( m_i, val );
	m_j = CMathFixed16::Mul( m_j, val );

	return *this;
}


inline
CVector2dFixed16& CVector2dFixed16::operator/=( fixed16 val )
{
	m_i = CMathFixed16::Div( m_i, val );
	m_j = CMathFixed16::Div( m_j, val );

	return *this;
}


inline
fixed16& CVector2dFixed16::operator[]( uint32 idx )
{
	ASSERT( idx < 2 );

	return *( ( (fixed16*)this ) + idx );
}


inline
fixed16 CVector2dFixed16::operator[]( uint32 idx ) const
{
	ASSERT( idx < 2 );

	return *( ( (fixed16*)this ) + idx );
}


inline 
CVector2dFixed16 operator+( const CVector2dFixed16& v1, const CVector2dFixed16& v2 )
{ 
	return CVector2dFixed16( v1.m_i + v2.m_i, v1.m_j + v2.m_j ); 
}


inline 
CVector2dFixed16 operator+( const CVector2dFixed16& v, fixed16 val )
{ 
	return CVector2dFixed16( v.m_i + val, v.m_j + val ); 
}


inline 
CVector2dFixed16 operator+( fixed16 val, const CVector2dFixed16& v )
{ 
	return CVector2dFixed16( val + v.m_i, val + v.m_j ); 
}


inline 
CVector2dFixed16 operator-( const CVector2dFixed16& v1, const CVector2dFixed16& v2 )
{ 
	return CVector2dFixed16( v1.m_i - v2.m_i,  v1.m_j - v2.m_j ); 
}


inline 
CVector2dFixed16 operator-( const CVector2dFixed16& v, fixed16 val )
{ 
	return CVector2dFixed16( v.m_i - val, v.m_j - val ); 
}


inline 
CVector2dFixed16 operator-( fixed16 val, const CVector2dFixed16& v )
{ 
	return CVector2dFixed16( val - v.m_i, val - v.m_j ); 
}


inline
fixed16 operator*( const CVector2dFixed16& v1, const CVector2dFixed16& v2 )
{
	return CMathFixed16::Mul( v1.m_i, v2.m_i ) + CMathFixed16::Mul( v1.m_j, v2.m_j );
}


inline
CVector2dFixed16 operator*( const CVector2dFixed16& v, fixed16 val )
{
	return CVector2dFixed16( CMathFixed16::Mul( v.m_i, val ), CMathFixed16::Mul( v.m_j, val ) );
}


inline
CVector2dFixed16 operator*( fixed16 val, const CVector2dFixed16& v )
{
	return CVector2dFixed16( CMathFixed16::Mul( val, v.m_i ), CMathFixed16::Mul( val, v.m_j ) );
}


inline
CVector2dFixed16 operator/( const CVector2dFixed16& v, fixed16 val )
{
	return CVector2dFixed16( CMathFixed16::Div( v.m_i, val ), CMathFixed16::Div( v.m_j, val ) );
}


inline
CVector2dFixed16 operator/( fixed16 val, const CVector2dFixed16& v )
{
	return CVector2dFixed16( CMathFixed16::Div( val, v.m_i ), CMathFixed16::Div( val, v.m_j ) );
}

inline
boolean operator==( const CVector2dFixed16& v1, const CVector2dFixed16& v2 )
{
    return v1.m_i == v2.m_i && v1.m_j == v2.m_j;
}

inline
boolean operator!=( const CVector2dFixed16& v1, const CVector2dFixed16& v2 )
{
    return !(v1 == v2);
}



 

#endif // __CVECTOR2DFIXED16_H__
